package controller;
import java.util.ArrayList;

import model.AIShrink;
import model.Bar;
import model.Block;
import model.Coin;
import model.Goal;
import model.Map;
import model.Point2;
import model.Puck;
import model.ScoreDecrease;
import model.ScoreIncrease;
import model.UserBar;
import model.UserShrink;


import java.util.ArrayList;


public class PhysicsEngine
{
        private boolean collision;
        private int index;
        private String type;
        
        private final int UP = 0;
        private final int DOWN = 600;
        private final int LEFT = 0;
        private final int RIGHT = 400;
        private final int BAR_LEFT = 100;
        private final int BAR_RIGHT = 300;
        
        public PhysicsEngine()
        {
                collision = false;
                index = -1;
                type = "";
        }
        
        public void refresh()
        {
                collision = false;
                index = -1;
                type = "";
        }
        
        public boolean getCollision()
        {
                return collision;
        }
        
        public int getIndex()
        {
                return index;
        }
        
        public String getType()
        {
                return type;
        }

        public void detectAndHandleEdgeCollision(Map map)
        {
                Puck puck = map.getPuck();
                
                if(puck.getX() < LEFT)
                {
                        puck.setX(1);
                        
                        if(puck.getComponentX() < 0)
                                puck.setComponentX((-1)*puck.getComponentX());
                }
                
                if(puck.getX() + puck.getDimX() > RIGHT)
                {
                        puck.setX(RIGHT - puck.getDimX() - 1);
                        
                        if(puck.getComponentX() > 0)
                                puck.setComponentX((-1)*puck.getComponentX());
                }
                
                if(puck.getY() < UP)
                {
                        puck.setY(1);
                        
                        if(puck.getComponentY() < 0)
                                puck.setComponentY((-1)*puck.getComponentY());
                }
                
                if(puck.getY() + puck.getDimY() > DOWN)
                {
                        puck.setY(DOWN - puck.getDimY() - 1);
                        
                        if(puck.getComponentY() > 0)
                        {
                                puck.setComponentY((-1)*puck.getComponentY());
                        }
                }
                
                ArrayList<Bar> bars = map.getBars();
                
                for(Bar bar : bars)
                {
                        if(bar.getX() < BAR_LEFT)
                                bar.setX(BAR_LEFT + 1);
                        
                        if(bar.getX() + bar.getDimX() > BAR_RIGHT)
                                bar.setX(BAR_RIGHT - (bar.getDimX() + 1));
                }
        }
        
        public void detectAndHandleCollision(Map map)
        {
                Puck puck = map.getPuck();
                ArrayList<Bar> bars = map.getBars();
                ArrayList<Goal> goals = map.getGoals();
                ArrayList<Coin> coins = map.getCoins();
                ArrayList<Block> blocks = map.getBlocks();
                
                Point2 minPuck = new Point2(puck.getX(), puck.getY());
                Point2 maxPuck = new Point2(puck.getX() + puck.getDimX(), puck.getY() + puck.getDimY());
                Point2 minObj = new Point2();
                Point2 maxObj = new Point2();
                
                if(puck.getY() == Double.NaN)
                        puck.setY(1);
                
                for(int i = 0; i < blocks.size(); ++i)
                {
                        if(blocks.get(i).isVisible())
                        {
                                minObj.setX(blocks.get(i).getX());
                                minObj.setY(blocks.get(i).getY());
                                maxObj.setX(blocks.get(i).getX() + blocks.get(i).getDimX());
                                maxObj.setY(blocks.get(i).getY() + blocks.get(i).getDimY());
                                
                                double dist = minObj.distance(maxObj);
                                dist = dist/2;
                                
                                if((maxPuck.getX() > minObj.getX()) && (minPuck.getX() < maxObj.getX()) && (maxPuck.getY() > minObj.getY()) && (minPuck.getY() < maxObj.getY())) // checks if rectangular boundaries collide
                                        if((minPuck.getX() + puck.getRadius() > minObj.getX() + ((blocks.get(i).getDimX())/2)) && ((puck.getY() + puck.getRadius()) < (minObj.getY() + ((blocks.get(i).getDimY())/2)))) // checks if puck is to the right of the rectangular object
                                                if(((Math.pow((minObj.getX() + blocks.get(i).getDimX()/2) - (minPuck.getX() + puck.getRadius()), 2)) + (Math.pow((minObj.getY() + blocks.get(i).getDimY()/2) - (minPuck.getY() + puck.getRadius()), 2))) < Math.pow(puck.getRadius() + dist, 2))
                                                        if((minPuck.getY() + puck.getRadius()) < (((-1)*blocks.get(i).getDimY()/blocks.get(i).getDimX())*(minPuck.getX() + puck.getRadius() - (minObj.getX() + blocks.get(i).getDimX()/2)) + minObj.getY() + blocks.get(i).getDimY()/2))
                                                        {
                                                                System.out.println("collision found 1 y");
                                                                this.collision = true;
                                                                this.index = i;
                                                                this.type = "block";
                                                                puck.setY(minObj.getY() - (puck.getDimY() + 1));
                                                                
                                                                if(puck.getComponentY() > 0)
                                                                        puck.setComponentY((-1)*puck.getComponentY());
                                                        }
                                                        else
                                                        {
                                                                System.out.println("collision found 1 x ");
                                                                this.collision = true;
                                                                this.index = i;
                                                                this.type = "block";
                                                                puck.setX(maxObj.getX() + 1);
                                                                
                                                                if(puck.getComponentX() < 0)
                                                                        puck.setComponentX((-1)*puck.getComponentX());
                                                        }
                                                else
                                                {
                                                        this.collision = false;
                                                        this.index = -1;
                                                        this.type = "";
                                                }
                                        else if(((minPuck.getX() + puck.getRadius()) > (minObj.getX() + ((blocks.get(i).getDimX())/2))) && ((minPuck.getY() + puck.getRadius()) > (minObj.getY() + ((blocks.get(i).getDimY())/2))))
                                                if(((Math.pow((minObj.getX() + blocks.get(i).getDimX()/2) - (minPuck.getX() + puck.getRadius()), 2)) + (Math.pow((minObj.getY() + blocks.get(i).getDimY()/2) - (minPuck.getY() + puck.getRadius()), 2))) < Math.pow(puck.getRadius() + dist, 2))
                                                        if((minPuck.getY() + puck.getRadius()) > ((blocks.get(i).getDimY()/blocks.get(i).getDimX())*(minPuck.getX() + puck.getRadius() - minObj.getX() - blocks.get(i).getDimX()/2) + minObj.getY() + blocks.get(i).getDimY()/2))
                                                        {
                                                                System.out.println("collision found 2 y");
                                                                this.collision = true;
                                                                this.index = i;
                                                                this.type = "block";
                                                                puck.setY(maxObj.getY() + 1);
                                                                
                                                                if(puck.getComponentY() < 0)
                                                                        puck.setComponentY((-1)*puck.getComponentY());
                                                        }
                                                        else
                                                        {
                                                                System.out.println("collision found 2 x");
                                                                this.collision = true;
                                                                this.index = i;
                                                                this.type = "block";
                                                                puck.setX(maxObj.getX() + 1);
                                                                
                                                                if(puck.getComponentX() < 0)
                                                                        puck.setComponentX((-1)*puck.getComponentX());
                                                        }
                                                else
                                                {
                                                        this.collision = false;
                                                        this.index = -1;
                                                        this.type = "";
                                                }
                                        else if((minPuck.getX() + puck.getRadius() < minObj.getX() + ((blocks.get(i).getDimX())/2)) && ((puck.getY() + puck.getRadius()) > (minObj.getY() + ((blocks.get(i).getDimY())/2))))
                                                if(((Math.pow((minObj.getX() + blocks.get(i).getDimX()/2) - (minPuck.getX() + puck.getRadius()), 2)) + (Math.pow((minObj.getY() + blocks.get(i).getDimY()/2) - (minPuck.getY() + puck.getRadius()), 2))) < Math.pow(puck.getRadius() + dist, 2))
                                                        if((minPuck.getY() + puck.getRadius()) > (((-1)*blocks.get(i).getDimY()/blocks.get(i).getDimX())*(minPuck.getX() + puck.getRadius() - minObj.getX() - blocks.get(i).getDimX()/2) + minObj.getY() + blocks.get(i).getDimY()/2))
                                                        {
                                                                System.out.println("collision found 3 y");
                                                                this.collision = true;
                                                                this.index = i;
                                                                this.type = "block";
                                                                puck.setY(maxObj.getY() + 1);
                                                                
                                                                if(puck.getComponentY() < 0)
                                                                        puck.setComponentY((-1)*puck.getComponentY());
                                                        }
                                                        else
                                                        {
                                                                System.out.println("collision found 3 x");
                                                                this.collision = true;
                                                                this.index = i;
                                                                this.type = "block";
                                                                puck.setX(minObj.getX() - puck.getDimX() - 1);
                                                                
                                                                if(puck.getComponentX() > 0)
                                                                        puck.setComponentX((-1)*puck.getComponentX());
                                                        }
                                                else
                                                {
                                                        this.collision = false;
                                                        this.index = -1;
                                                        this.type = "";
                                                }
                                        else
                                                if(((Math.pow((minObj.getX() + blocks.get(i).getDimX()/2) - (minPuck.getX() + puck.getRadius()), 2)) + (Math.pow((minObj.getY() + blocks.get(i).getDimY()/2) - (minPuck.getY() + puck.getRadius()), 2))) < Math.pow(puck.getRadius() + dist, 2))
                                                        if((minPuck.getY() + puck.getRadius()) < ((blocks.get(i).getDimY()/blocks.get(i).getDimX())*(minPuck.getX() + puck.getRadius() - minObj.getX() - blocks.get(i).getDimX()/2) + minObj.getY() + blocks.get(i).getDimY()/2))
                                                        {
                                                                System.out.println("collision found 4 y");
                                                                this.collision = true;
                                                                this.index = i;
                                                                this.type = "block";
                                                                puck.setY(minObj.getY() - puck.getDimY() - 1);
                                                                
                                                                if(puck.getComponentY() > 0)
                                                                        puck.setComponentY((-1)*puck.getComponentY());
                                                        }
                                                        else
                                                        {
                                                                System.out.println("collision found 4 x");
                                                                this.collision = true;
                                                                this.index = i;
                                                                this.type = "block";
                                                                puck.setX(minObj.getX() - puck.getDimX() - 1);
                                                                
                                                                if(puck.getComponentX() > 0)
                                                                        puck.setComponentX((-1)*puck.getComponentX());
                                                        }
                                                else
                                                {
                                                        this.collision = false;
                                                        this.index = -1;
                                                        this.type = "";
                                                }
                                else
                                {
                                        this.collision = false;
                                        this.index = -1;
                                        this.type = "";
                                }
                                                
                                if(collision)
                                {
                                        blocks.get(index).gotHit();
                                }
                                
                        }
                                                
                }
                
                for(int j = 0; j < coins.size(); ++j)
                {
                        if(coins.get(j).getVisibility())
                        {
                                minObj.setX(coins.get(j).getX());
                                minObj.setY(coins.get(j).getY());
                                maxObj.setX(coins.get(j).getX() + coins.get(j).getDimX());
                                maxObj.setY(coins.get(j).getY() + coins.get(j).getDimY());
                                
                                if(Math.sqrt(Math.pow(minPuck.getX() - minObj.getX(), 2) + Math.pow(minPuck.getY() - minObj.getY(), 2)) < (puck.getRadius() + (coins.get(j).getDimY())/2))
                                {
                                        int flag = coins.get(j).getType();
                                        
                                        switch(flag) {
                                        case 10:
                                                bars.get(1).setVisibility(false);
                                                map.modifyCoinCounter(0, 12000);
                                                coins.get(j).setVisibility(false);
                                                break;
                                        case 20:
                                                bars.get(1).setDimX(((AIShrink)coins.get(j)).getShrinkX());
                                                map.modifyCoinCounter(1, 12000);
                                                bars.get(1).changeImage("AIBar-Shrinked.png");
                                                coins.get(j).setVisibility(false);
                                                break;
                                        case 30:
                                                ((UserBar)bars.get(0)).setCoeff(1);
                                                map.modifyCoinCounter(2, 12000);
                                                coins.get(j).setVisibility(false);
                                                break;
                                        case 40:
                                                map.addUserScore(((ScoreIncrease)coins.get(j)).generateBonus());
                                                coins.get(j).setVisibility(false);
                                                break;
                                        case -10:
                                                bars.get(0).setVisibility(false);
                                                map.modifyCoinCounter(4, 12000);
                                                coins.get(j).setVisibility(false);
                                                break;
                                        case -20:
                                                bars.get(0).setDimX(((UserShrink)coins.get(j)).getShrinkX());
                                                map.modifyCoinCounter(5, 12000);
                                                bars.get(0).changeImage("UserBarDefault-Shrinked.png");
                                                coins.get(j).setVisibility(false);
                                                break;
                                        case -30:
                                                ((UserBar)bars.get(0)).setCoeff(-1);
                                                map.modifyCoinCounter(6, 12000);
                                                coins.get(j).setVisibility(false);
                                                break;
                                        case -40:
                                                map.addUserScore(((ScoreDecrease)coins.get(j)).generateDecrease());
                                                coins.get(j).setVisibility(false);
                                                break;
                                        default:
                                                break;
                                        }
                                }
                        }
                }
                
                for(int k = 0; k < bars.size(); ++k)
                {
                        if(bars.get(k).isVisible())
                        {
                                minObj.setX(bars.get(k).getX());
                                minObj.setY(bars.get(k).getY());
                                maxObj.setX(bars.get(k).getX() + bars.get(k).getDimX());
                                maxObj.setY(bars.get(k).getY() + bars.get(k).getDimY());
                                
                                double dist = minObj.distance(maxObj);
                                dist = dist/2;
                                
                                if((maxPuck.getX() > minObj.getX()) && (minPuck.getX() < maxObj.getX()) && (maxPuck.getY() > minObj.getY()) && (minPuck.getY() < maxObj.getY())) // checks if rectangular boundaries collide
                                        if((minPuck.getX() + puck.getRadius() > minObj.getX() + ((bars.get(k).getDimX())/2)) && ((puck.getY() + puck.getRadius()) < (minObj.getY() + ((bars.get(k).getDimY())/2)))) // checks if puck is to the right of the rectangular object
                                                if(((Math.pow((minObj.getX() + bars.get(k).getDimX()/2) - (minPuck.getX() + puck.getRadius()), 2)) + (Math.pow((minObj.getY() + bars.get(k).getDimY()/2) - (minPuck.getY() + puck.getRadius()), 2))) < Math.pow(puck.getRadius() + dist, 2))
                                                        if((minPuck.getY() + puck.getRadius()) < (((-1)*bars.get(k).getDimY()/bars.get(k).getDimX())*(minPuck.getX() + puck.getRadius() - minObj.getX() - bars.get(k).getDimX()/2) + minObj.getY() + bars.get(k).getDimY()/2))
                                                        {
                                                                System.out.println("collision found 1 y");
                                                                this.collision = true;
                                                                this.index = k;
                                                                this.type = "bar";
                                                                puck.setY(minObj.getY() - puck.getDimY() - 1);
                                                                
                                                                if(puck.getComponentY() > 0)
                                                                        puck.setComponentY((-1)*puck.getComponentY());
                                                        }
                                                        else
                                                        {
                                                                System.out.println("collision found 1 x");
                                                                this.collision = true;
                                                                this.index = k;
                                                                this.type = "bar";
                                                                puck.setX(maxObj.getX() + 1);
                                                                
                                                                if(puck.getComponentX() < 0)
                                                                        puck.setComponentX((-1)*puck.getComponentX());
                                                        }
                                                else
                                                {
                                                        this.collision = false;
                                                        this.index = -1;
                                                        this.type = "";
                                                }
                                        else if((minPuck.getX() + puck.getRadius() > minObj.getX() + ((bars.get(k).getDimX())/2)) && ((puck.getY() + puck.getRadius()) > (minObj.getY() + ((bars.get(k).getDimY())/2))))
                                                if(((Math.pow((minObj.getX() + bars.get(k).getDimX()/2) - (minPuck.getX() + puck.getRadius()), 2)) + (Math.pow((minObj.getY() + bars.get(k).getDimY()/2) - (minPuck.getY() + puck.getRadius()), 2))) < Math.pow(puck.getRadius() + dist, 2))
                                                        if((minPuck.getY() + puck.getRadius()) > ((bars.get(k).getDimY()/bars.get(k).getDimX())*(minPuck.getX() + puck.getRadius() - minObj.getX() - bars.get(k).getDimX()/2) + minObj.getY() + bars.get(k).getDimY()/2))
                                                        {
                                                                System.out.println("collision found 2 y");
                                                                this.collision = true;
                                                                this.index = k;
                                                                this.type = "block";
                                                                System.out.println(puck.getY());
                                                                puck.setY(maxObj.getY() + 1);

                                                                if(puck.getComponentY() < 0)
                                                                        puck.setComponentY((-1)*puck.getComponentY());
                                                                
                                                                System.out.println(puck.getY() + "  " + puck.getComponentY());
                                                        }
                                                        else
                                                        {
                                                                System.out.println("collision found 2 x");
                                                                this.collision = true;
                                                                this.index = k;
                                                                this.type = "block";
                                                                puck.setX(maxObj.getX() + 1);
                                                                
                                                                if(puck.getComponentX() < 0)
                                                                puck.setComponentX((-1)*puck.getComponentX());
                                                        }
                                                else
                                                {
                                                        this.collision = false;
                                                        this.index = -1;
                                                        this.type = "";
                                                }
                                        else if((minPuck.getX() + puck.getRadius() < minObj.getX() + ((bars.get(k).getDimX())/2)) && ((puck.getY() + puck.getRadius()) > (minObj.getY() + ((bars.get(k).getDimY())/2))))
                                                if(((Math.pow((minObj.getX() + bars.get(k).getDimX()/2) - (minPuck.getX() + puck.getRadius()), 2)) + (Math.pow((minObj.getY() + bars.get(k).getDimY()/2) - (minPuck.getY() + puck.getRadius()), 2))) < Math.pow(puck.getRadius() + dist, 2))
                                                        if((minPuck.getY() + puck.getRadius()) > (((-1)*bars.get(k).getDimY()/bars.get(k).getDimX())*(minPuck.getX() + puck.getRadius() - minObj.getX() - bars.get(k).getDimX()/2) + minObj.getY() + bars.get(k).getDimY()/2))
                                                        {
                                                                System.out.println("collision found 3 y");
                                                                this.collision = true;
                                                                this.index = k;
                                                                this.type = "block";
                                                                puck.setY(maxObj.getY() + 1);
                                                                
                                                                if(puck.getComponentY() < 0)
                                                                        puck.setComponentY((-1)*puck.getComponentY());
                                                        }
                                                        else
                                                        {
                                                                System.out.println("collision found 3 x");
                                                                this.collision = true;
                                                                this.index = k;
                                                                this.type = "block";
                                                                puck.setX(minObj.getX() - puck.getDimX() - 1);
                                                                
                                                                if(puck.getComponentX() > 0)
                                                                        puck.setComponentX((-1)*puck.getComponentX());
                                                        }
                                                else
                                                {
                                                        this.collision = false;
                                                        this.index = -1;
                                                        this.type = "";
                                                }
                                        else
                                                if(((Math.pow((minObj.getX() + bars.get(k).getDimX()/2) - (minPuck.getX() + puck.getRadius()), 2)) + (Math.pow((minObj.getY() + bars.get(k).getDimY()/2) - (minPuck.getY() + puck.getRadius()), 2))) < Math.pow(puck.getRadius() + dist, 2))
                                                        if((minPuck.getY() + puck.getRadius()) < ((bars.get(k).getDimY()/bars.get(k).getDimX())*(minPuck.getX() + puck.getRadius() - minObj.getX() - bars.get(k).getDimX()/2) + minObj.getY() + bars.get(k).getDimY()/2))
                                                        {
                                                                System.out.println("collision found 4 y");
                                                                this.collision = true;
                                                                this.index = k;
                                                                this.type = "block";
                                                                puck.setY(minObj.getY() - puck.getDimY() - 1);
                                                                
                                                                if(puck.getComponentY() > 0)
                                                                        puck.setComponentY((-1)*puck.getComponentY());
                                                        }
                                                        else
                                                        {
                                                                System.out.println("collision found 4 x");
                                                                this.collision = true;
                                                                this.index = k;
                                                                this.type = "block";
                                                                puck.setX(minObj.getX() - puck.getDimX() - 1);
                                                                
                                                                if(puck.getComponentX() > 0)
                                                                        puck.setComponentX((-1)*puck.getComponentX());
                                                        }
                                                else
                                                {
                                                        this.collision = false;
                                                        this.index = -1;
                                                        this.type = "";
                                                }
                                else
                                {
                                        this.collision = false;
                                        this.index = -1;
                                        this.type = "";
                                }
                                                
                                if(collision)
                                {
                                        if(bars.get(index).getSpeedState() > 0)
                                        {
                                                double mag = puck.getMagnitude();
                                                double xComp = puck.getComponentX();
                                                double yComp = puck.getComponentY();
                                                
                                                xComp += bars.get(index).getComponentX()*0.1;
                                                
                                                yComp = Math.sqrt(Math.abs(mag*mag - xComp*xComp));
                                                
                                                puck.setComponentX(xComp);
                                                puck.setComponentY(yComp);
                                        }
                                        
                                }
                        }
                }               
        }

}
